#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/ledc.h"
#include "esp_log.h"

// 配置参数
#define PWM_GPIO         0          // PWM输出引脚
#define PWM_FREQ_HZ      20000       // 20KHz频率
#define PWM_CHANNEL      0           // 通道编号（0-7）
#define PWM_TIMER        0           // 定时器编号（0-3）
#define PWM_RESOLUTION   LEDC_TIMER_10_BIT // 10位分辨率（0-1023）
#define PWM_MODE         0           // v5.5.0中模式用数值0表示（替代LEDC_MODE_LOW）

static const char *TAG = "pwm_20khz";

// 初始化PWM配置
static void pwm_init(void) {
    // 1. 配置定时器
    ledc_timer_config_t timer_config = {
        .timer_num        = PWM_TIMER,             // 定时器编号
        .duty_resolution  = PWM_RESOLUTION,        // 分辨率
        .freq_hz          = PWM_FREQ_HZ,           // 20KHz频率
        .clk_cfg          = LEDC_AUTO_CLK          // 自动选择时钟源
    };
    ESP_ERROR_CHECK(ledc_timer_config(&timer_config));

    // 2. 配置通道
    ledc_channel_config_t channel_config = {
        .channel        = PWM_CHANNEL,             // 通道编号
        .timer_sel      = PWM_TIMER,               // 绑定的定时器
        .intr_type      = LEDC_INTR_DISABLE,       // 禁用中断
        .gpio_num       = PWM_GPIO,                // 输出引脚
        .duty           = 0,                       // 初始占空比（0）
        .hpoint         = 0                        // 忽略hpoint
    };
    ESP_ERROR_CHECK(ledc_channel_config(&channel_config));

    ESP_LOGI(TAG, "PWM初始化完成：%dHz @ GPIO%d", PWM_FREQ_HZ, PWM_GPIO);
}

// 设置PWM占空比（0-100%）
static void set_pwm_duty(float duty_percent) {
    if (duty_percent < 0 || duty_percent > 100) {
        ESP_LOGE(TAG, "占空比超出范围（0-100）");
        return;
    }
    // 计算占空比数值（基于10位分辨率）
    uint32_t duty = (uint32_t)(duty_percent / 100.0f * ((1 << PWM_RESOLUTION) - 1));
    // 使用数值0作为模式参数（适配v5.5.0）
    ESP_ERROR_CHECK(ledc_set_duty(PWM_MODE, PWM_CHANNEL, duty));
    ESP_ERROR_CHECK(ledc_update_duty(PWM_MODE, PWM_CHANNEL)); // 更新占空比
    ESP_LOGI(TAG, "占空比设置为：%.1f%%（数值：%d）", duty_percent, duty);
}

void app_main(void) {
    // 初始化PWM
    pwm_init();

    // 循环改变占空比演示
    while (1) {
        set_pwm_duty(20.0f);   // 20%占空比
        vTaskDelay(2000 / portTICK_PERIOD_MS);

        set_pwm_duty(50.0f);   // 50%占空比
        vTaskDelay(2000 / portTICK_PERIOD_MS);

        set_pwm_duty(80.0f);   // 80%占空比
        vTaskDelay(2000 / portTICK_PERIOD_MS);
    }
}
